//
// Created by jetkey on 18-8-13.
//

#include <jni.h>

#define __android

#include "testsuit_framework.h"

#include "log_helper.hpp"


static int _width = 640;
static int _height = 480;

extern TestCase testList[];

void myprint(JNIEnv *env,jobject me, int type, const char* buff){
    jclass clazz = env->GetObjectClass(me);
    if(type<=1) {
        jmethodID meth = env->GetMethodID(clazz, "print", "(ILjava/lang/String;)I");
        //
        jstring str = env->NewStringUTF(buff);
        env->CallIntMethod(me, meth, type, str);
        //
        env->DeleteLocalRef(str);
    }

    env->DeleteLocalRef(clazz);
}

static uint8_t *buffRgb=NULL;
static uint8_t *buffDep=NULL;
static uint8_t *buffOut=NULL;

extern "C" JNIEXPORT jint JNICALL Java_com_imi_sdk_jnitest_MainActivity_getTestCount(JNIEnv *env,jobject me){
    TestCase *p = testList;
    int i=0;
    while(p->name!=NULL){
        i++;
        p++;
        LOGDS("i=",i)
    }
    return i;
}

extern "C" JNIEXPORT jstring JNICALL Java_com_imi_sdk_jnitest_MainActivity_getTestName(JNIEnv *env,jobject me,jint i){
    TestCase &testCase = testList[i];
    jstring res = env->NewStringUTF(testCase.name);
    return res;
}



#include <memory.h>

#include "usbdevice/ImiDefines.h"
#include "usbdevice/ImiNect.h"
#include "usbdevice/ImiProperties.h"
#include "usbdevice/ImiCamera.h"

ImiStream* pDepStream =0;
ImiDevice* pDev =0;
ImiCamera* pCam=0;

inline void initBuffer(uint8_t **p){
    if(NULL==*p){
        *p = new uint8_t[_width*_height*6];
        memset(*p,0,_width*_height*6);
    }
}

#define SAFE_DELETE_ARRAY(p) \
    if(NULL!=p) { delete[] p; p = NULL; }

static int fps = 33;
extern "C" JNIEXPORT jboolean JNICALL Java_com_imi_sdk_jnitest_CameraPreviewFragment_initTest(JNIEnv *env,jobject me,jint i){
    TestCase &testCase = testList[i];
    fps = 33;
    //
    Printer f = std::bind(myprint,env,me,std::placeholders::_1,std::placeholders::_2);
    bool ok = testCase.initor(&(testCase.usrData),&fps,f);

    initBuffer(&buffRgb);
    initBuffer(&buffDep);
    initBuffer(&buffOut);

    pDepStream = 0;
    pDev = 0;
    pCam = 0;
    //
    return ok;
}

extern "C" JNIEXPORT jint JNICALL Java_com_imi_sdk_jnitest_CameraPreviewFragment_getFps(JNIEnv *env,jobject me){
    return fps;
}




extern "C" JNIEXPORT jint JNICALL Java_com_imi_sdk_jnitest_MainActivity_setHandles(JNIEnv *env,jobject me,jlong cam,jlong dev,jlong stream){
    pDepStream = (ImiStream*) stream;
    pCam = (ImiCamera*) cam;
    pDev = (ImiDevice*) dev;
    return 0;
}

static int readNextCameraFrame() {

    if(0==pDepStream || 0==pDev || 0==pCam){
        return -1;
    }
    //

    static uint64_t depth_t;
    static uint64_t color_t;
//
    ImiCameraFrame *pCameraFrame = NULL;
    int32_t rrt = imiCamReadNextFrame(pCam, &pCameraFrame, 30);
    if (0 == rrt && pCameraFrame != NULL && pCameraFrame->pData != NULL) {
        memcpy(buffRgb, (const void *) pCameraFrame->pData, pCameraFrame->size);
        //
        color_t = pCameraFrame->timeStamp;
        LOGD("color frame time stamp: %uld\n", color_t);
        imiCamReleaseFrame(&pCameraFrame);
    } else {
        return -2;
    }

    ImiImageFrame *pFrame = NULL;

    if (0 != imiReadNextFrame(pDepStream, &pFrame, 30)) {
        LOGD("depth frame fail")
//        return -3;
    }
    if (pFrame != NULL && pFrame->pData != NULL) {
        memcpy(buffDep, pFrame->pData, pFrame->size);
        depth_t = pFrame->timeStamp;
        LOGD("depth frame time stamp: %uld, %ld\n", depth_t, pFrame->size);
//        g_bDepthFrameOK = true;
        imiReleaseFrame(&pFrame);

    }
    return 0;
}

#include <map>

std::map<string,string> envValues;

extern "C" JNIEXPORT jstring JNICALL Java_com_imi_sdk_jnitest_CameraPreviewFragment_getEnv(JNIEnv *env,jobject me,jstring key){
    string k(env->GetStringUTFChars(key,0));
    auto r = envValues.find(k);
    if(r==envValues.end()){
        return 0;
    }else{
        return env->NewStringUTF(r->second.c_str());
    }
}


//char buff1[640*480*3];
extern "C" JNIEXPORT jboolean JNICALL Java_com_imi_sdk_jnitest_CameraPreviewFragment_stepTest(JNIEnv *env,jobject me,jint i){

    TestCase &testCase = testList[i];

    readNextCameraFrame();

//    memcpy(buff1,buffRgb,640*480*3);

    LOGIS(">>")
    Printer f = std::bind(myprint,env,me,std::placeholders::_1,std::placeholders::_2);
    bool ok = testCase.step(testCase.usrData,(char *)buffRgb,(char *)buffDep,(char *)buffOut,_width,_height,f);

    return ok;
}

extern "C" JNIEXPORT jint JNICALL Java_com_imi_sdk_jnitest_CameraPreviewFragment_endTest(JNIEnv *env,jobject me,jint i){
    TestCase &testCase = testList[i];
    Printer f = std::bind(myprint,env,me,std::placeholders::_1,std::placeholders::_2); //(env,me);
    testCase.ender(testCase.usrData,f);
    testCase.usrData = NULL;

    SAFE_DELETE_ARRAY(buffRgb)
    SAFE_DELETE_ARRAY(buffDep)
    SAFE_DELETE_ARRAY(buffOut)

    pDepStream = 0;
    pDev = 0;
    pCam = 0;

    return 1;
}

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
static bool _renderOnGl(void *img,int textureId){
    if(NULL==img){
        LOGD("wrong pixel format")
        return false;
    }
//    glActiveTexture(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,textureId);
    int fmt = GL_RGB;
    int bt = GL_UNSIGNED_BYTE;
    glTexSubImage2D(GL_TEXTURE_2D,0,0,0,_width,_height,fmt,bt,img);

    return true;
}

extern "C" JNIEXPORT jint JNICALL Java_com_imi_sdk_jnitest_CameraPreviewFragment_updateTexture(JNIEnv *env,jobject me,jint tid, jint chan){
    if(NULL!=buffRgb && tid>0 && chan == 0 ){
        _renderOnGl(buffRgb,tid);
    }
//    if(NULL!=buffDep && tid>0 && chan == 5){
//        _renderOnGl(buff1,tid);
//    }
    if(NULL!=buffOut && tid>0 && chan == 2){
        _renderOnGl(buffOut,tid);
    }
    if(NULL!=buffDep && tid>0 && chan == 1){
        uint16_t *p = (uint16_t*)buffDep;
        uint8_t buff[_width*_height*3];
        int N = _width*_height;
        for(int i=0;i<N;i++){
            int k = 3*i;
            uint16_t x = p[i];
            uint8_t r = x >> 4;
            buff[k+0] = r;
            buff[k+1] = r;
            buff[k+2] = 0;
        }
        //
        _renderOnGl(buff,tid);
    }
    return 1;
}



#include "testsuit_framework.h"
